package cn.edu.nwpu.warehousemanagement.config;

import cn.edu.nwpu.warehousemanagement.pojo.response.PublicKeyResponse;
import cn.edu.nwpu.warehousemanagement.util.LogUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import jakarta.annotation.PostConstruct;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicReference;

/**
 * Rsa密钥配置类
 *
 * @author Loadstar
 * @version 1.0
 */
@Component
public class RsaKeyConfig {
    // 最新私钥
    private final AtomicReference<String> newerPrivateKey = new AtomicReference<>();
    // 旧私钥，防止浏览器缓存导致解密失败
    private final AtomicReference<String> olderPrivateKey = new AtomicReference<>();
    // 最新公钥
    private final AtomicReference<String> currentPublicKey = new AtomicReference<>();

    @PostConstruct
    public void init() {
        generateNewKeys(); // 初始化生成第一个密钥
    }

    @Scheduled(cron = "${spring.task.scheduling.cron}") // 每天2点生成新密钥
    public void generateNewKeys() {
        RSA rsa = new RSA();
        String newPrivateKey = rsa.getPrivateKeyBase64();
        String newPublicKey = rsa.getPublicKeyBase64();


        olderPrivateKey.set(newerPrivateKey.get());
        newerPrivateKey.set(newPrivateKey);
        currentPublicKey.set(newPublicKey);

        LogUtil.info(RsaKeyConfig.class, "新密钥生成成功");
    }

    public PublicKeyResponse getPublicKey() {
        return new PublicKeyResponse(currentPublicKey.get());
    }

    public String decrypt(String encryptedData) {
        // 尝试最新私钥解密
        String privateKey = newerPrivateKey.get();
        // 下面方法虽然相同，但idea提不出来？？有多重出口
        if (privateKey != null) {
            try {
                RSA rsa = new RSA(privateKey, null);
                return rsa.decryptStr(encryptedData, KeyType.PrivateKey);
            } catch (Exception ignored) {

            }
        }

        // 尝试旧私钥解密
        privateKey = olderPrivateKey.get();
        if (privateKey != null) {
            try {
                RSA rsa = new RSA(privateKey, null);
                return rsa.decryptStr(encryptedData, KeyType.PrivateKey);
            } catch (Exception ignored) {

            }
        }

        throw new RuntimeException("无效的加密数据或公钥已过期");
    }
}
